package com.example.service;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 内存监控服务
 * 负责监控JVM和Redis的内存使用情况
 */
@Service
@Slf4j
public class MemoryMonitorService {

    @Autowired(required = false)
    private RedisTemplate<String, Object> redisTemplate;

    // 保存历史内存使用数据
    private final Map<String, List<MemorySnapshot>> memoryHistory = new ConcurrentHashMap<>();
    
    // 历史数据点数量限制
    private static final int MAX_HISTORY_POINTS = 48; // 保存48个数据点
    
    /**
     * 定时收集内存使用情况
     */
    @Scheduled(fixedRate = 1800000) // 每30分钟执行一次
    public void collectMemoryMetrics() {
        MemorySnapshot snapshot = takeMemorySnapshot(true);
        
        // 日志记录
        log.info("内存使用情况: JVM堆内存={}MB/{}MB (已提交:{}%, 最大:{}%), Redis内存={}MB",
                snapshot.getHeapUsed() / (1024 * 1024),
                snapshot.getHeapMax() / (1024 * 1024),
                snapshot.getHeapUsagePercent(),
                snapshot.getHeapMaxUsagePercent(),
                snapshot.getRedisUsed() / (1024 * 1024));
    }
    
    /**
     * 获取当前内存使用情况
     */
    public MemorySnapshot getCurrentMemoryUsage() {
        return takeMemorySnapshot(false);
    }
    
    /**
     * 获取内存使用历史记录
     */
    public Map<String, List<MemorySnapshot>> getMemoryHistory() {
        return memoryHistory;
    }
    
    /**
     * 获取当前内存快照
     * @param addToHistory 是否添加到历史记录
     */
    private MemorySnapshot takeMemorySnapshot(boolean addToHistory) {
        MemorySnapshot snapshot = new MemorySnapshot();
        snapshot.setTimestamp(System.currentTimeMillis());
        
        // 获取JVM内存信息
        MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
        MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage();
        
        snapshot.setHeapInit(heapMemoryUsage.getInit());
        snapshot.setHeapUsed(heapMemoryUsage.getUsed());
        snapshot.setHeapMax(heapMemoryUsage.getMax());
        snapshot.setHeapCommitted(heapMemoryUsage.getCommitted());
        
        // 计算基于已提交内存的使用百分比
        double committedUsagePercent = (double) heapMemoryUsage.getUsed() / heapMemoryUsage.getCommitted() * 100;
        snapshot.setHeapUsagePercent(Math.round(committedUsagePercent * 100) / 100.0); // 保留两位小数
        
        // 同时保存基于最大内存的使用百分比
        if (heapMemoryUsage.getMax() > 0) {
            double maxUsagePercent = (double) heapMemoryUsage.getUsed() / heapMemoryUsage.getMax() * 100;
            snapshot.setHeapMaxUsagePercent(Math.round(maxUsagePercent * 100) / 100.0); // 保留两位小数
        }
        
        // 获取非堆内存信息
        MemoryUsage nonHeapMemoryUsage = memoryMXBean.getNonHeapMemoryUsage();
        snapshot.setNonHeapUsed(nonHeapMemoryUsage.getUsed());
        snapshot.setNonHeapCommitted(nonHeapMemoryUsage.getCommitted());
        
        // 获取Redis内存信息(如果可用)
        if (redisTemplate != null) {
            try {
                Object info = redisTemplate.execute(
                        (connection) -> connection.serverCommands().info("memory"),
                        true
                );
                
                if (info != null) {
                    String infoStr = info.toString();
                    // 解析Redis INFO返回的内存使用信息
                    Map<String, String> parsedInfo = parseRedisInfo(infoStr);
                    
                    if (parsedInfo.containsKey("used_memory")) {
                        long usedMemory = Long.parseLong(parsedInfo.get("used_memory"));
                        snapshot.setRedisUsed(usedMemory);
                    }
                    
                    if (parsedInfo.containsKey("maxmemory")) {
                        long maxMemory = Long.parseLong(parsedInfo.get("maxmemory"));
                        snapshot.setRedisMax(maxMemory);
                        
                        if (maxMemory > 0) {
                            double redisUsagePercent = (double) snapshot.getRedisUsed() / maxMemory * 100;
                            snapshot.setRedisUsagePercent(Math.round(redisUsagePercent * 100) / 100.0);
                        }
                    }
                }
            } catch (Exception e) {
                log.warn("获取Redis内存信息失败: {}", e.getMessage());
            }
        }
        
        // 仅当需要时才添加到历史记录
        if (addToHistory) {
            String currentDay = String.format("%tF", System.currentTimeMillis());
            memoryHistory.computeIfAbsent(currentDay, k -> new LinkedList<>()).add(snapshot);
            
            // 限制每天的历史记录数量
            List<MemorySnapshot> dayHistory = memoryHistory.get(currentDay);
            if (dayHistory.size() > MAX_HISTORY_POINTS) {
                dayHistory.remove(0); // 移除最旧的记录
            }
            
            // 清理过期的历史记录(7天前)
            long sevenDaysAgo = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);
            memoryHistory.entrySet().removeIf(entry -> {
                try {
                    String dateStr = entry.getKey();
                    // 简单解析日期格式 yyyy-MM-dd
                    String[] parts = dateStr.split("-");
                    if (parts.length == 3) {
                        int year = Integer.parseInt(parts[0]);
                        int month = Integer.parseInt(parts[1]) - 1; // 月份从0开始
                        int day = Integer.parseInt(parts[2]);
                        
                        long dateMillis = new java.util.GregorianCalendar(year, month, day).getTimeInMillis();
                        return dateMillis < sevenDaysAgo;
                    }
                    return false;
                } catch (Exception e) {
                    return false;
                }
            });
        }
        
        return snapshot;
    }
    
    /**
     * 解析Redis INFO命令返回的信息
     */
    private Map<String, String> parseRedisInfo(String info) {
        Map<String, String> result = new HashMap<>();
        if (info == null || info.isEmpty()) {
            return result;
        }
        
        String[] lines = info.split("\r\n");
        for (String line : lines) {
            if (line.isEmpty() || line.startsWith("#")) {
                continue;
            }
            
            String[] parts = line.split(":");
            if (parts.length == 2) {
                result.put(parts[0], parts[1]);
            }
        }
        
        return result;
    }
    
    /**
     * 内存使用情况快照
     */
    @Data
    public static class MemorySnapshot {
        private long timestamp;
        
        // JVM堆内存
        private long heapInit;
        private long heapUsed;
        private long heapCommitted;
        private long heapMax;
        
        // 基于已提交内存的使用百分比（实际分配给JVM的内存）
        private double heapUsagePercent;
        
        // 基于最大内存的使用百分比（JVM理论上可以使用的最大内存）
        private double heapMaxUsagePercent;
        
        // JVM非堆内存
        private long nonHeapUsed;
        private long nonHeapCommitted;
        
        // Redis内存
        private long redisUsed;
        private long redisMax;
        private double redisUsagePercent;
    }
}